package cn.regexp.seckill.web.controller;


import cn.regexp.common.core.constants.CommonConstants;
import cn.regexp.common.core.domain.UserInfo;
import cn.regexp.common.core.exception.BusinessException;
import cn.regexp.common.core.web.Result;
import cn.regexp.common.core.web.anno.RequireLogin;
import cn.regexp.seckill.domain.OrderInfo;
import cn.regexp.seckill.enums.SeckillRedisKeyEnum;
import cn.regexp.seckill.mq.MQConstant;
import cn.regexp.seckill.mq.OrderMessage;
import cn.regexp.seckill.service.IOrderInfoService;
import cn.regexp.seckill.service.ISeckillProductService;
import cn.regexp.seckill.util.UserUtil;
import cn.regexp.seckill.web.msg.SeckillCodeMsg;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author Regexpei
 * @date 2024/7/6 11:09
 * @description 订单信息控制器
 */
@RestController
@RequestMapping("/order")
@Slf4j
public class OrderInfoController {
    @Autowired
    private ISeckillProductService seckillProductService;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @SuppressWarnings("AlibabaLowerCamelCaseVariableNaming")
    @Autowired
    private RocketMQTemplate rocketMQTemplate;
    @Autowired
    private IOrderInfoService orderInfoService;

    /**
     * 库存本地标识
     */
    public static ConcurrentHashMap<Long, Boolean> seckillProductStock = new ConcurrentHashMap<>();

    @RequireLogin
    @PostMapping("/doSeckill")
    public Result<String> doSeckill(int time, Long seckillId, HttpServletRequest request) {
        // 校验参数
        if (StringUtils.isEmpty(time + "") || StringUtils.isEmpty(seckillId + "")) {
            throw new BusinessException(SeckillCodeMsg.OPT_ERROR);
        }

        // 判断是否在活动时间内 todo 测试
        // SeckillProductVo vo = seckillProductService.find(time, seckillId);
        // if (!DateUtil.isLegalTime(vo.getStartDate(), time)) {
        //     throw new BusinessException(SeckillCodeMsg.OPT_ERROR);
        // }

        // 从本地标识中获取指定秒杀商品的状态，true 表示商品库存小于 0
        Boolean isStock = seckillProductStock.get(seckillId);
        // 判断库存是否不足
        if (isStock != null && isStock) {
            throw new BusinessException(SeckillCodeMsg.SECKILL_STOCK_OVER);
        }

        // 获取 redis 中的秒杀商品库存数量
        Long count = redisTemplate.opsForHash()
                .increment(SeckillRedisKeyEnum.SECKILL_STOCK_COUNT_HASH.getRealKey(time + ""), seckillId + "", -1L);
        // 判断秒杀商品是否有库存
        if (count < 0) {
            seckillProductStock.put(seckillId, true);
            throw new BusinessException(SeckillCodeMsg.SECKILL_STOCK_OVER);
        }

        // 判断是否为重复下单
        // seckillProductSet:time  phone:seckillId
        String token = request.getHeader(CommonConstants.TOKEN_NAME);
        UserInfo userInfo = UserUtil.getUser(redisTemplate, token);
        Boolean flag = redisTemplate.opsForSet().isMember(SeckillRedisKeyEnum.SECKILL_PRODUCT_SET.getRealKey(time + ""),
                userInfo.getPhone() + ":" + seckillId);
        if (Boolean.TRUE.equals(flag)) {
            throw new BusinessException(SeckillCodeMsg.REPEAT_SECKILL);
        }

        // 秒杀逻辑
        // 创建 message 并封装数据
        OrderMessage message = new OrderMessage();
        message.setSeckillId(seckillId);
        message.setTime(time);
        message.setToken(token);
        message.setUserPhone(userInfo.getPhone());
        // 发送异步消息
        rocketMQTemplate.sendOneWay(MQConstant.ORDER_PEDDING_TOPIC, message);
        return Result.success("您的订单正在处理中...");
    }

    @RequestMapping("/find")
    public Result<OrderInfo> find(String orderNo, HttpServletRequest request) {
        // 判断是否有传进来 orderNo
        if (StringUtils.isEmpty(orderNo)) {
            throw new BusinessException(SeckillCodeMsg.OPT_ERROR);
        }
        OrderInfo orderInfo = orderInfoService.find(orderNo);
        // 判断是否存在对应的订单信息
        if (ObjectUtils.isEmpty(orderInfo)) {
            throw new BusinessException(SeckillCodeMsg.OPT_ERROR);
        }

        UserInfo userInfo = UserUtil.getUser(redisTemplate, request.getHeader(CommonConstants.TOKEN_NAME));
        // 判断订单信息的用户是否与登录用户一致
        if (!orderInfo.getUserId().equals(userInfo.getPhone())) {
            throw new BusinessException(SeckillCodeMsg.OPT_ERROR);
        }
        return Result.success(orderInfo);
    }
}
